package data;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import core.Log;

public class EventDateTime implements Cloneable
{
	private GregorianCalendar calen;
	private long timeInMilli;
	private static final SimpleDateFormat ISO_DATE_TIME = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
	private static final SimpleDateFormat ISO_DATE = new SimpleDateFormat("yyyy-MM-dd");

	static {
		ISO_DATE_TIME.setLenient(false);
		ISO_DATE.setLenient(false);
		Log.warn("Date and time variables are NOT set to lenient");
	}

	public EventDateTime() {
		Log.debug("EDT: Entering default constructor");
		calen = new GregorianCalendar(1970, 0, 1, 0, 0);
		calen.setLenient(true);
		timeInMilli = calen.getTimeInMillis();
	}

	public EventDateTime(long timeInMillis) {
		Log.debug("EDT: Entering constructor with time in millis as param");
		calen = new GregorianCalendar(1970, 0, 1, 0, 0);
		calen.setTimeInMillis(timeInMillis);
		calen.setLenient(true);
		timeInMilli = calen.getTimeInMillis();
	}

	public EventDateTime(int year, int month, int dayOfMonth) {
		Log.debug("EDT: Entering constructor with year, month and day as param");
		calen = new GregorianCalendar(year, month-1, dayOfMonth, 0, 0);
		calen.setLenient(false);
		timeInMilli = calen.getTimeInMillis();

	}

	public EventDateTime(int year, int month, int dayOfMonth, int hourOfDay,
			int minute) {
		Log.debug("EDT: Entering constructor with year, month, day, hour and minute as param");
		calen = new GregorianCalendar(year, month-1, dayOfMonth, hourOfDay, minute);
		calen.setLenient(false);
		timeInMilli = calen.getTimeInMillis();
	}

	public EventDateTime(int year, int month, int dayOfMonth, int hourOfDay,
			int minute, int second) {
		Log.debug("EDT: Entering constructor with year, month, day, hour, minute and second as param");
		calen = new GregorianCalendar(year, month-1, dayOfMonth, hourOfDay, minute, second);
		calen.setLenient(false);
		timeInMilli = calen.getTimeInMillis();
	}

	public static EventDateTime current() {
		Log.debug("EDT: Entering current");
		Calendar curr = Calendar.getInstance();
		EventDateTime currTime = new EventDateTime(curr.get(Calendar.YEAR), curr.get(Calendar.MONTH) +1 , curr.get(Calendar.DAY_OF_MONTH),
				curr.get(Calendar.HOUR_OF_DAY), curr.get(Calendar.MINUTE), curr.get(Calendar.SECOND));
		return currTime;
	}
	public int get(int property) {
		Log.debug("EDT: Entering get");
		int value = calen.get(property);
		if (property == Calendar.MONTH) {
			value += 1;
		}
		return value;
	}

	public void set(int field, int value) {
		Log.debug("EDT: Entering set");
		if (field == Calendar.MONTH) {
			value -= 1;
		}
		Log.warn("EDT: function set will set field to value provided");
		calen.set(field, value);
		timeInMilli = calen.getTimeInMillis();
	}

	public void set(int year, int month, int day) {

		Log.warn("EDT: function sets year, month and day based on values provided");
		calen.set(year, month - 1, day);
		timeInMilli = calen.getTimeInMillis();
	}

	public void set(int year, int month, int day, int hourOfDay, int minute) {
		
		Log.warn("EDT: function sets year, month, day, hour and minute based on values provided");
		calen.set(year, month - 1, day, hourOfDay, minute);
		timeInMilli = calen.getTimeInMillis();
	}

	public void set(int year, int month, int day, int hourOfDay, int minute, int second) {
		
		Log.warn("EDT: function sets year, month, day, hour, minute and second based on values provided");
		calen.set(year, month - 1, day, hourOfDay, minute, second);
		timeInMilli = calen.getTimeInMillis();
	}

	@Override
	public boolean equals(Object obj) {
		Log.debug("EDT: entering equals");
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof EventDateTime)) {
			return false;
		}
		EventDateTime gc = (EventDateTime) obj;
		return this.getTimeInMilli() == gc.getTimeInMilli();
	}

	public String toString() {
		Log.debug("EDT: entering toString");
		return getTimeInMilli() + "";//calen.toString();
	}

	public void setTime(long time) {
		Log.debug("EDT: entering setTime");
		this.timeInMilli = time;
		calen.setTimeInMillis(time);
	}

	public long getTimeInMilli() {
		Log.debug("EDT: entering getTimeInMilli");
		return timeInMilli;
	}

	public void setTimeInMilli(long time) {
		Log.debug("EDT: entering setTimeInMilli");
		this.timeInMilli = time;
		calen.setTimeInMillis(time);
	}
	
	public String getDisplayName (int field, int style) {
		Log.debug("EDT: entering getDisplayName");
		return calen.getDisplayName(field, style, Locale.getDefault());
	}

	public long compareTo(EventDateTime current) {
		Log.debug("EDT: entering compareTo comparing two EDT objects");
		return this.getTimeInMilli() - current.getTimeInMilli();
	}

	public void inc(int field) {
		Log.debug("EDT: entering inc");
		this.add(field, 1);
	}

	public void add(int field, int value) {
		Log.debug("EDT: entering add");
		this.calen.add(field, value);
		timeInMilli = this.calen.getTimeInMillis();
	}

	public String toDateTimeXML() {
		Log.debug("EDT: entering toDateTimeXML");
		return ISO_DATE_TIME.format(new Date(timeInMilli));
	}

	public String toDateXML() {
		Log.debug("EDT: entering toDateXML");
		return ISO_DATE.format(new Date(timeInMilli));
	}
	
	public static EventDateTime xmlToEventTime(String xml) {
		Log.debug("EDT: entering xmlToEventTime");
		Date date;
		date = xmlToDateObj(xml);
		if (date == null) {
			return null;
		}
		return new EventDateTime(date.getTime());
	}

	private static Date xmlToDateObj(String xml) {
		try {
			return ISO_DATE_TIME.parse(xml);
		} catch (ParseException e) {
			try {
				return ISO_DATE.parse(xml);
			} catch (ParseException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
				return null;
			}
		}
	}
	
	public EventDateTime getTime() {
		Log.debug("EDT: entering getTime");
		EventDateTime newEventTime = new EventDateTime();
		newEventTime.set(Calendar.HOUR_OF_DAY, this.get(Calendar.HOUR_OF_DAY));
		newEventTime.set(Calendar.MINUTE, this.get(Calendar.MINUTE));
		newEventTime.getTimeInMilli();
		return newEventTime;
	}
	
	public EventDateTime getDate() {
		return new EventDateTime(this.get(Calendar.YEAR), this.get(Calendar.MONTH), this.get(Calendar.DAY_OF_MONTH)); 		
	}

	public boolean isDefaultTime() {
		return this.equals(new EventDateTime());
	}
	
}
